using System;
using System.Collections;
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace CGF
{
    public static class InputFieldExtensions
    {
        public static void SetInputAction(this InputField inputField, Action<string> callback, bool showInputField)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.showInputField = showInputField;
            listener.onInput = callback;
        }

        public static void SetInputEndAction(this InputField inputField, Action callback, bool showInputField)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.showInputField = showInputField;
            listener.onInputEnd = callback;
        }

        public static void SetKeyboardShowAction(this InputField inputField, Action callback, bool showInputField)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.showInputField = showInputField;
            listener.onKeyboardShow = callback;
        }

        public static void SetKeyboardHideActio(this InputField inputField, Action callback, bool showInputField)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.showInputField = showInputField;
            listener.onKeyboardHide = callback;
        }

        public static void SetLongPressAction(this InputField inputField, Action callback)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.onLongPressAction = callback;
        }

        public static void SetPress(this InputField inputField, Action callback)
        {
            InputEndListener listener = inputField.GetComponent<InputEndListener>();
            if (!listener) listener = inputField.gameObject.AddComponent<InputEndListener>();
            listener.onPress = callback;
        }
    }

    [RequireComponent(typeof(InputField))]
    public class InputEndListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
        public Action<string> onInput;
        public Action onKeyboardShow, onKeyboardHide, onInputEnd, onLongPressAction, onPress;

        public bool showInputField;
        private static RectTransform inputGuide;
        private InputField inputField;
        private bool wasKeyboardVisible, hasTriggerEndEvent, isPointerDown;
        private float pointerDownTimer;
        private Canvas _canvas;
#if UNITY_WEBGL
        private static int defaultWindowHeight;
#endif

        private void Awake()
        {
            inputField = GetComponent<InputField>();
            inputField.onValueChanged.AddListener(OnInput);
            inputField.onEndEdit.AddListener(OnInputEnd);
#if UNITY_WEBGL
            defaultWindowHeight = Application.isEditor ? 0 : JSHelper.GetWindowInnerHeight();
#endif
        }

        void Update()
        {
            bool isKeyboardVisible = TouchScreenKeyboard.visible;
            if (isKeyboardVisible != wasKeyboardVisible)
            {
                wasKeyboardVisible = isKeyboardVisible;
                if (isKeyboardVisible)
                {
                    OnKeyboardShow();
                }
            }
            if (isPointerDown)
            {
                if (Time.time - pointerDownTimer > 0.5f)
                {
                    isPointerDown = false;
                    if (inputField.enabled)
                    {
                        onLongPressAction?.Invoke();
                    }
                }
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            onPress?.Invoke();
            isPointerDown = true;
            pointerDownTimer = Time.time;
        }
        public void OnPointerUp(PointerEventData eventData)
        {
            isPointerDown = false;
            pointerDownTimer = 0f;
        }

        private void OnKeyboardShow()
        {
            //键盘弹起
            hasTriggerEndEvent = false;
            if (showInputField && !Define.IsWebGL)
            {
                ShowInputCanvas();
            }
            onKeyboardShow?.Invoke();
            if (Application.isMobilePlatform && !Define.IsWebGL)
            {
                StartCoroutine(CheckKeyboardStatusOnAppOnly());
            }
        }

        public async void ShowInputCanvas()
        {
            if (!inputGuide)
            {
                GameObject prefab = await ResManager.Instance.LoadAsset<GameObject>("Prefabs/Common/InputCanvas");
                GameObject go = Instantiate(prefab);
                DontDestroyOnLoad(go);
                inputGuide = go.Get<RectTransform>("InputField");
            }
            inputGuide.DOAlpha(0);
            await CTask.Wait(0.3f);
            if (hasTriggerEndEvent) return;
            inputGuide.transform.parent.gameObject.SetActive(true);
            inputGuide.DOAlpha(1, 0.3f);
            if (!_canvas)
            {
                _canvas = GetComponentInParent<CanvasScaler>().GetComponent<Canvas>();
            }
            float uiHeight = (_canvas.transform as RectTransform).sizeDelta.y;
            // float uikeyboardH = GetKeyboardHeight() * uiHeight / (float)Screen.height;
            inputGuide.anchoredPosition = new Vector2(0, 580);
        }

        IEnumerator CheckKeyboardStatusOnAppOnly()
        {
            yield return new WaitForSeconds(1f);
            while (GetKeyboardHeight() > 300)
            {
                yield return new WaitForSeconds(0.2f);
            }

            EventSystem.current.SetSelectedGameObject(null);
            inputField.OnDeselect(null);
            OnInputEnd(inputField.text);
        }

        private void OnInput(string content)
        {
            if (inputGuide)
            {
                inputGuide.GetComponent<InputField>().text = content;
            }
            hasTriggerEndEvent = false;
            onInput?.Invoke(content);
        }

        private void OnInputEnd(string content)
        {
            if (!hasTriggerEndEvent)
            {
                if (inputGuide)
                {
                    inputGuide.DOKill();
                    inputGuide.transform.parent.gameObject.SetActive(false);
                }
                hasTriggerEndEvent = true;
                onKeyboardHide?.Invoke();
                onInputEnd?.Invoke();
            }
        }

        private void OnDestroy()
        {
            inputField.onValueChanged.RemoveListener(OnInput);
            inputField.onEndEdit.RemoveListener(OnInputEnd);
        }

        public static int GetKeyboardHeight()
        {
            int height = 0;
            if (!Application.isEditor)
            {
#if UNITY_ANDROID
                using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                using (AndroidJavaObject rootView = currentActivity.Call<AndroidJavaObject>("getWindow").Call<AndroidJavaObject>("getDecorView"))
                using (AndroidJavaObject rect = new AndroidJavaObject("android.graphics.Rect"))
                {
                    rootView.Call("getWindowVisibleDisplayFrame", rect);
                    int screenHeight = rootView.Call<int>("getHeight");
                    int visibleHeight = rect.Call<int>("height");
                    height = Mathf.Max(0, screenHeight - visibleHeight);
                }
#elif UNITY_IOS
                if (TouchScreenKeyboard.visible) 
                {
                    Rect area = TouchScreenKeyboard.area;
                    height = (int)area.height;
                }
#elif UNITY_WEBGL
                height = defaultWindowHeight - JSHelper.GetWindowInnerHeight();
#endif
            }
            Debug.Log("Keyboard height: " + height);
            return height;
        }
    }
}
